//拓展功能部分
#include "gpio_p.h"

GPIO_TypeDef *gpio_group[5] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE};

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     GPIO输出设置
// 参数说明     pin         引脚号选择的引脚 (可选择范围由 stm32f10x_gpio.h 内 gpio_pin_enum枚举值确定)
// 参数说明     dat         引脚的电平状态，输出时有效 0：低电平 1：高电平
// 返回参数     void
// 使用示例     gpio_set_level(D0, 0);//D0输出低电平
//-------------------------------------------------------------------------------------------------------------------
void gpio_set_level(gpio_pin_enum pin, uint8_t dat)
{
    if(dat)
    {
        gpio_high(pin);                                                         // 输出高电平
    }
    else
    {
        gpio_low(pin);                                                          // 输出低电平
    }
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     GPIO状态获取
// 参数说明     pin         选择的引脚 (可选择范围由 stm32f10x_gpio.h 内 gpio_pin_enum枚举值确定)
// 返回参数     uint8       0：低电平 1：高电平
// 使用示例     uint8 status = gpio_get_level(D0);//获取D0引脚电平
//-------------------------------------------------------------------------------------------------------------------
uint8_t gpio_get_level(gpio_pin_enum pin)
{
    return ((gpio_group[(pin & 0xE0) >> 5]->IDR & (((uint16_t)0x0001) << (pin & 0x1F))) ? 1 : 0);
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     GPIO 翻转
// 参数说明     pin         选择的引脚 (可选择范围由 stm32f10x_gpio.h 内 gpio_pin_enum枚举值确定)
// 返回参数     void        
// 使用示例     gpio_toggle_level(D5);//D5引脚电平翻转
//-------------------------------------------------------------------------------------------------------------------
void gpio_toggle_level(gpio_pin_enum pin)
{
    uint8_t io_group = (pin & 0xE0) >> 5;
    uint8_t io_pin = pin & 0x1F;

    ((gpio_group[io_group]))->ODR ^= (uint16_t)(1 << io_pin);
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     gpio 方向设置
// 参数说明     pin         选择的引脚 (可选择范围由 stm32f10x_gpio.h 内 gpio_pin_enum 枚举值确定)
// 参数说明     dir         引脚的方向   输出：GPO   输入：GPI
// 参数说明     mode        引脚的模式 输出速度默认50MHz,可用|单独设置(可选择范围由 stm32f10x_gpio.h 内 gpio_mode_enum 枚举值确定)
// 返回参数     void
// 使用示例     gpio_set_dir(D5, GPI, GPI_PULL_UP);                             // 设置 D5 为上拉输入
// 备注信息
//-------------------------------------------------------------------------------------------------------------------
void gpio_set_dir (gpio_pin_enum pin, gpio_dir_enum dir, gpio_mode_enum mode)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    uint8_t io_group = (pin & 0xE0) >> 5;
    uint8_t io_pin = pin & 0x1F;

    // 设置引脚号
    GPIO_InitStructure.GPIO_Pin = (uint16_t)(1 << io_pin);

    // 只有输出需要设置速度
    if(GPO == dir)
    {
        if((uint16_t)mode >> 8 == 0) GPIO_InitStructure.GPIO_Speed = (GPIOSpeed_TypeDef)(GPIO_Speed_50MHz);    // 防止没有填写这个参数,默认设置50Mhz
        else GPIO_InitStructure.GPIO_Speed = (gpio_speed_enum)((uint16_t)mode >> 8);                           // 已经填写了该参数。根据值来设置
    }

    // 设置模式
    GPIO_InitStructure.GPIO_Mode = (GPIOMode_TypeDef)((uint16_t)mode & 0xFF);
    GPIO_Init(gpio_group[io_group], &GPIO_InitStructure);
}

//-------------------------------------------------------------------------------------------------------------------
// 函数简介     GPIO初始化
// 参数说明     pin         选择的引脚 (可选择范围由 stm32f10x_gpio.h 内 gpio_pin_enum枚举值确定)
// 参数说明     dir         引脚的方向   输出：GPO   输入：GPI
// 参数说明     dat         引脚初始化时设置的电平状态，输出时有效 0：低电平 1：高电平
// 参数说明     pinconf     输出速度默认50MHz,可用|单独设置 引脚配置（可设置参数由stm32f10x_gpio.h文件内GPIOSPEED_enum与GPIOMODE_enum枚举值确定，多个条件使用 | 相或）
// 返回参数     void
// 使用示例     gpio_init(D0, GPO, 1, GPIO_PIN_CONFIG);//D0初始化为GPIO功能、输出模式、输出高电平、速度100MHZ 推挽输出
//-------------------------------------------------------------------------------------------------------------------
void gpio_init (gpio_pin_enum pin, gpio_dir_enum dir, const uint8_t dat, gpio_mode_enum mode)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    uint8_t io_group = (pin & 0xE0) >> 5;
    uint8_t io_pin = pin & 0x1F;

    // GPIO总线使能
    if(0 == io_group)      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    else if(1 == io_group) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    else if(2 == io_group) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    else if(3 == io_group) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    else if(4 == io_group) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);

    if(pin =  A15)
    {
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
    }
    // 设置引脚号
    GPIO_InitStructure.GPIO_Pin = (uint16_t)(1 << io_pin);

    // 只有输出需要设置速度
    if(GPO == dir)
    {
        if((uint16_t)mode >> 8 == 0) GPIO_InitStructure.GPIO_Speed = (GPIOSpeed_TypeDef)(GPIO_Speed_50MHz);    // 防止没有填写这个参数,默认设置50Mhz
        else GPIO_InitStructure.GPIO_Speed = (gpio_speed_enum)((uint16_t)mode >> 8);                           // 已经填写了该参数。根据值来设置
    }

    // 设置模式
    GPIO_InitStructure.GPIO_Mode = (GPIOMode_TypeDef)((uint16_t)mode & 0xFF);
    GPIO_Init(gpio_group[io_group], &GPIO_InitStructure);

    // 只有输出需要设置引脚状态
    if(GPO == dir)
    {
        GPIO_WriteBit(gpio_group[io_group], (uint16_t)(1 << io_pin), dat);
    }
}


